home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / dalla rivista / host contacted / jikes.lha / jikes-1.11 / src / incrmnt.cpp < prev    next >
C/C++ Source or Header  |  1999-10-18  |  16KB  |  427 lines

  1. // $Id: incrmnt.cpp,v 1.12 1999/10/18 16:51:03 shields Exp $
  2. //
  3. // This software is subject to the terms of the IBM Jikes Compiler
  4. // License Agreement available at the following URL:
  5. // http://www.ibm.com/research/jikes.
  6. // Copyright (C) 1996, 1998, International Business Machines Corporation
  7. // and others.  All Rights Reserved.
  8. // You must accept the terms of that agreement to use this software.
  9. //
  10. #include "config.h"
  11. #include <sys/stat.h>
  12. #include <iostream.h>
  13. #include "control.h"
  14. #include "scanner.h"
  15. #include "parser.h"
  16. #include "semantic.h"
  17. #include "case.h"
  18. #include "set.h"
  19.  
  20. void Control::RemoveTrashedTypes(SymbolSet &type_trash_set)
  21. {
  22.     TypeSymbol *type;
  23.  
  24.     //
  25.     // For each type T that is going to be trashed, and for each parent P of T that
  26.     // is not itself being trashed, remove T from the set of dependents of P.
  27.     // If T is a subtype of P it is also removed from the subtypes set.
  28.     //
  29.     for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
  30.     {
  31.         for (TypeSymbol *static_parent = (TypeSymbol *) type -> static_parents -> FirstElement();
  32.                          static_parent;
  33.                          static_parent = (TypeSymbol *) type -> static_parents -> NextElement())
  34.         {
  35.             if (! type_trash_set.IsElement(static_parent))
  36.             {
  37.                 static_parent -> dependents -> RemoveElement(type);
  38.                 static_parent -> subtypes -> RemoveElement(type);
  39.             }
  40.         }
  41.  
  42.         for (TypeSymbol *parent = (TypeSymbol *) type -> parents -> FirstElement();
  43.                          parent;
  44.                          parent = (TypeSymbol *) type -> parents -> NextElement())
  45.         {
  46.             if (! type_trash_set.IsElement(parent))
  47.             {
  48.                 parent -> dependents -> RemoveElement(type);
  49.                 parent -> subtypes -> RemoveElement(type);
  50.             }
  51.         }
  52.     }
  53.  
  54.     //
  55.     // We can now safely delete the type.
  56.     //
  57.     for (type = (TypeSymbol *) type_trash_set.FirstElement(); type; type = (TypeSymbol *) type_trash_set.NextElement())
  58.     {
  59.         PackageSymbol *package = type -> ContainingPackage();
  60.  
  61.         //
  62.         // If a type that is about to be trashed was read in via a class file, remove the class file.
  63.         // Note that invoking RemoveElement for a file that it does not contain has no ill effect.
  64.         //
  65.         FileSymbol *file_symbol = type -> file_symbol;
  66.         if (file_symbol && type -> Identity() == file_symbol -> Identity())
  67.             input_class_file_set.RemoveElement(file_symbol);
  68.  
  69.         //
  70.         // If a type that is about to be trashed was contained in the unnamed_package,
  71.         // remove it from the set "unnamed_package_types"
  72.         //
  73.         if (package == unnamed_package)
  74.             unnamed_package_types.RemoveElement(type);
  75.  
  76.         //
  77.         // Remove the type from its containing package.
  78.         //
  79.         package -> DeleteTypeSymbol(type);
  80.     }
  81.  
  82.     return;
  83. }
  84.  
  85.  
  86. inline DirectoryEntry *Control::FindInputFile(FileSymbol *file_symbol)
  87. {
  88.     int length = file_symbol -> Utf8NameLength() + FileSymbol::java_suffix_length;
  89.  
  90.     char *java_name = new char[length + 1]; // +1 for '\0'
  91.     strcpy(java_name, file_symbol -> Utf8Name());
  92.     strcat(java_name, FileSymbol::java_suffix);
  93.  
  94.     DirectoryEntry *java_entry = file_symbol -> directory_symbol -> FindEntry(java_name, length);
  95.  
  96.     delete [] java_name;
  97.  
  98.     return java_entry;
  99.  
  100. }
  101.  
  102.  
  103. //
  104. // For each file whose associated source (".java") has changed, add it to the list to be recompiled...
  105. //
  106. void Control::FindMoreRecentInputFiles(SymbolSet &file_candidates)
  107. {
  108.     for (FileSymbol *file_symbol = (FileSymbol *) file_candidates.FirstElement();
  109.                      file_symbol;
  110.                      file_symbol = (FileSymbol *) file_candidates.NextElement())
  111.     {
  112.         //
  113.         // If the type is not zipped and it is not already contained in the recompilation set, then check it...
  114.         //
  115.         if ((! file_symbol -> IsZip()) &&
  116.             (! recompilation_file_set.IsElement(file_symbol)) &&
  117.             (! expired_file_set.IsElement(file_symbol)))
  118.         {
  119.             //
  120.             // If there is no java source file or its time stamp is not newer than file_symbol then
  121.             // reset file_symbol to NULL. Otherwise, reset file symbol to the newer file.
  122.             //
  123.             DirectoryEntry *java_entry = FindInputFile(file_symbol);
  124.             if (! java_entry)
  125.             {
  126.                 if (file_symbol -> IsJava()) // A source file that was compiled in the previous pass no longer exists.
  127.                     expired_file_set.AddElement(file_symbol);
  128.             }
  129.             else if (java_entry -> Mtime() > file_symbol -> mtime) // a newer file was found
  130.             {
  131.                  file_symbol -> mtime = java_entry -> Mtime();
  132.                  recompilation_file_set.AddElement(file_symbol);
  133.             }
  134.         }
  135.     }
  136.  
  137.     return;
  138. }
  139.  
  140.  
  141. void Control::RereadDirectory(DirectorySymbol *directory_symbol)
  142. {
  143.     directory_symbol -> ResetDirectory();
  144.  
  145.     for (int i = 0; i < directory_symbol -> subdirectories.Length(); i++)
  146.         RereadDirectory(directory_symbol -> subdirectories[i]);
  147.  
  148.     return;
  149. }
  150.  
  151.  
  152. void Control::RereadDirectories()
  153. {
  154.     for (int i = (dot_classpath_index == 0 ? 0 : 1); i < classpath.Length(); i++)
  155.     {
  156.         PathSymbol *path_symbol = classpath[i];
  157.         if (! path_symbol -> IsZip())
  158.             RereadDirectory(path_symbol -> RootDirectory());
  159.     }
  160.  
  161.     return;
  162. }
  163.  
  164.  
  165. void Control::ComputeRecompilationSet(TypeDependenceChecker &dependence_checker)
  166. {
  167.     SymbolSet type_trash_set;
  168.  
  169.     //
  170.     // Find out if any source files has been touched since the last compilation and
  171.     // add all such files to recompilation_file_set.
  172.     //
  173.     FindMoreRecentInputFiles(dependence_checker.file_set);
  174.  
  175.     //
  176.     // Before messing with the files, compute a list of all the types that have just been compiled.
  177.     // We need to do this here as we will be "Resetting" and "reScanning" some files in the loop below,
  178.     // which in effect removes the set of types to which they were associated in the previous compilation.
  179.     //
  180.     int length_estimate = input_java_file_set.Size(); // an estimate of the size of the problem
  181.     Tuple<TypeSymbol *> input_types(length_estimate * 2);
  182.     for (FileSymbol *file_symbol = (FileSymbol *) input_java_file_set.FirstElement();
  183.                      file_symbol;
  184.                      file_symbol = (FileSymbol *) input_java_file_set.NextElement())
  185.     {
  186.         for (int i = 0; i < file_symbol -> types.Length(); i++)
  187.             input_types.Next() = file_symbol -> types[i];
  188.     }
  189.  
  190.     //
  191.     // Declare the closure set, and initialize it with the Union over the closure of the
  192.     // types in the trash_bin. Essentially, we want to catch all "compiled" types in the
  193.     // compilation that has a dependence on these bad types.
  194.     //
  195.     SymbolSet dependents_closure(length_estimate);
  196.     for (int i = 0; i < type_trash_bin.Length(); i++)
  197.     {
  198.         TypeSymbol *type = type_trash_bin[i];
  199.         if (! dependents_closure.IsElement(type))
  200.         {
  201.             if (type -> dependents_closure)
  202.                  dependents_closure.Union(*(type -> dependents_closure));
  203.             else dependents_closure.AddElement(type);
  204.         }
  205.     }
  206.  
  207.     //
  208.     // Compute the set of types from the recompilation set that needs to be recompiled
  209.     // and update the recompilation file set.
  210.     //
  211.     SymbolSet new_set(length_estimate),
  212.               file_seen(length_estimate);
  213.     new_set = recompilation_file_set;
  214.     new_set.Union(expired_file_set);
  215.     file_seen = new_set;
  216.  
  217.     StoragePool *ast_pool = new StoragePool(64); // how much space do we need for a package declaration? estimate 64 tokens.
  218.  
  219.     //
  220.     // As long as there is a new_set of files to process,...
  221.     //
  222.     do
  223.     {
  224.         //
  225.         // For each file in new_set, compute the reflexive transitive closure of all types contained in that file.
  226.         // Next, reset and rescan the file. If the scan was successful, iterate over the new list of types to see
  227.         // if any of them had already been introduced in the previous compilation via a class file. If so, add all such
  228.         // types to the dependents closure.
  229.         //
  230.         for (FileSymbol *file_symbol = (FileSymbol *) new_set.FirstElement();
  231.                          file_symbol;
  232.                          file_symbol = (FileSymbol *) new_set.NextElement())
  233.         {
  234.             for (int i = 0; i < file_symbol -> types.Length(); i++)
  235.             {
  236.                 TypeSymbol *type = file_symbol -> types[i];
  237.                 if (! dependents_closure.IsElement(type))
  238.                 {
  239.                     if (type -> dependents_closure)
  240.                          dependents_closure.Union(*(type -> dependents_closure));
  241.                     else dependents_closure.AddElement(type);
  242.                 }
  243.             }
  244.  
  245.             if (! expired_file_set.IsElement(file_symbol))
  246.             {
  247.                 file_symbol -> Reset();
  248.                 file_symbol -> SetJava();
  249.  
  250.                 scanner -> Scan(file_symbol);
  251.  
  252.                 LexStream *lex_stream = file_symbol -> lex_stream;
  253.                 if (lex_stream) // did we have a successful scan!
  254.                 {
  255.                     AstPackageDeclaration *package_declaration = parser -> PackageHeaderParse(lex_stream, ast_pool);
  256.                     PackageSymbol *package = (package_declaration
  257.                                                   ? FindOrInsertPackage(lex_stream, package_declaration -> name) : unnamed_package);
  258.                     ast_pool -> Reset();
  259.  
  260.                     //
  261.                     // If the file contained more than one type, only the main one would have
  262.                     // been deleted. We now delete the others if any...
  263.                     //
  264.                     for (int k = 0; k < lex_stream -> NumTypes(); k++)
  265.                     {
  266.                         LexStream::TokenIndex identifier_token = lex_stream -> Next(lex_stream -> Type(k));
  267.                         if (lex_stream -> Kind(identifier_token) == TK_Identifier)
  268.                         {
  269.                             NameSymbol *name_symbol = lex_stream -> NameSymbol(identifier_token);
  270.                             TypeSymbol *type = package -> FindTypeSymbol(name_symbol);
  271.                             if (type && (! dependents_closure.IsElement(type)))
  272.                             {
  273.                                 if (type -> dependents_closure)
  274.                                      dependents_closure.Union(*(type -> dependents_closure));
  275.                                 else dependents_closure.AddElement(type);
  276.                             }
  277.                         }
  278.                     }
  279.                 }
  280.             }
  281.         }
  282.  
  283.         //
  284.         // Iterate over the dependents_closure set. For each type T, add it to the trash pile.
  285.         // If the file with which it is associated had not yet been processed, mark it as having
  286.         // been "seen" and add it to the new_set to be considered later.
  287.         // If the file had already been processed but not yet added to the recompilation set,
  288.         // add it to the recompilation set, read it in and if it contains types other than the
  289.         // the main one (that had previously been read in via class files) add those new types
  290.         // to the trash pile.
  291.         //
  292.         new_set.SetEmpty();
  293.         for (TypeSymbol *type = (TypeSymbol *) dependents_closure.FirstElement();
  294.                          type;
  295.                          type = (TypeSymbol *) dependents_closure.NextElement())
  296.         {
  297.             type_trash_set.AddElement(type);
  298.  
  299.             FileSymbol *file_symbol = type -> file_symbol;
  300.             if (file_symbol && (! file_seen.IsElement(file_symbol)))
  301.             {
  302.                 file_seen.AddElement(file_symbol);
  303.                 new_set.AddElement(file_symbol);
  304.                 file_symbol -> mtime = 0; // to force a reread of the file.
  305.             }
  306.         }
  307.  
  308.         //
  309.         // Check that the files in new_set exist, and if so, add them to the recompilation_file_set.
  310.         // Note that if they exist, they will be added because before a file is added to new_set
  311.         // its time stamp is reset to 0. See loop above...
  312.         //
  313.         FindMoreRecentInputFiles(new_set);
  314.  
  315.         //
  316.         // Empty out the dependents_closure set for the next round.
  317.         //
  318.         dependents_closure.SetEmpty();
  319.     } while (! new_set.IsEmpty());
  320.  
  321.     delete ast_pool;
  322.  
  323.     //
  324.     // Clean up the types that were compiled in the previous compilation pass.
  325.     //
  326.     for (int j = 0; j < input_types.Length(); j++)
  327.         input_types[j] -> RemoveCompilationReferences();
  328.  
  329.     //
  330.     // Reset the closure sets in all the types that were considered in the dependence checker.
  331.     //
  332.     Tuple<TypeSymbol *> &type_list = dependence_checker.TypeList();
  333.     for (int k = 0; k < type_list.Length(); k++)
  334.     {
  335.         TypeSymbol *type = type_list[k];
  336.  
  337.         type -> index = CycleChecker::OMEGA;
  338.         type -> unit_index = CycleChecker::OMEGA;
  339.         type -> incremental_index = CycleChecker::OMEGA;
  340.         delete type -> dependents_closure;
  341.         type -> dependents_closure = NULL;
  342.     }
  343.  
  344.     //
  345.     // Remove all dependence edges that are no longer valid.
  346.     //
  347.     RemoveTrashedTypes(type_trash_set);
  348.  
  349.     return;
  350. }
  351.  
  352.  
  353. //
  354. // Check whether or not there are files to be rempiled.
  355. //
  356. bool Control::IncrementalRecompilation()
  357. {
  358.     //
  359.     // Empty out the type lookup table so that it does not continue
  360.     // to point to a type that is deleted here.
  361.     //
  362.     type_table.SetEmpty();
  363.  
  364.     SymbolSet candidates(input_java_file_set.Size() + input_class_file_set.Size() + recompilation_file_set.Size());
  365.     ArgumentExpander *new_arguments = NULL;
  366.  
  367.     if (! recompilation_file_set.IsEmpty())
  368.         candidates = recompilation_file_set;
  369.     else
  370.     {
  371.         fprintf(stderr, "\nIncremental Jikes: Press Enter to continue or [Q]uit + Enter to exit: ");
  372.         fflush(stderr);
  373.  
  374.         Tuple<char> line;
  375.         char ch;
  376.         cin.get(ch);
  377.         while(ch != U_ESCAPE && ch != U_LINE_FEED)
  378.         {
  379.             line.Next() = ch;
  380.             cin.get(ch);
  381.         }
  382.         if (ch == U_ESCAPE)
  383.             return false;
  384.  
  385.         new_arguments = new ArgumentExpander(line);
  386.         char q[2] = {U_q, U_NU};
  387.         if (new_arguments -> argc == 1 && (Case::StringEqual(new_arguments -> argv[0], U8S_quit) ||
  388.                                            Case::StringSegmentEqual(new_arguments -> argv[0], q, 2)))
  389.         {
  390.             delete new_arguments;
  391.             return false;
  392.         }
  393.  
  394.         candidates = input_java_file_set;
  395.         candidates.Union(input_class_file_set);
  396.     }
  397.  
  398.     if ((! candidates.IsEmpty()) || (new_arguments && new_arguments -> argc > 0))
  399.     {
  400.         TypeDependenceChecker dependence_checker((Control *) this, candidates, type_trash_bin);
  401.         dependence_checker.PartialOrder();
  402.  
  403.         //
  404.         // Compute the initial set of files that need to be recompiled. Place them in recompilation_file_set.
  405.         //
  406.         RereadDirectories();
  407.  
  408.         if (new_arguments)
  409.             ProcessNewInputFiles(recompilation_file_set, *new_arguments);
  410.  
  411.         ComputeRecompilationSet(dependence_checker);
  412.     }
  413.  
  414.     //
  415.     // Starting with the initial recompilation_file_set, complete the computation of the
  416.     // set of files that need to be recompiled. (Add all new files to recompilation_file_set)
  417.     // Also, complete the computation of type_trash_set, the set of files that should be
  418.     // removed from the database as they will be recompiled.
  419.     //
  420.     fprintf(stderr, "%s", (recompilation_file_set.IsEmpty() && expired_file_set.IsEmpty() ? "\nnothing changed...\n" : "\nok...\n"));
  421.     fflush(stderr);
  422.  
  423.     delete new_arguments;
  424.  
  425.     return true;
  426. }
  427.